#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <sys/time.h>

#include "slowcat.h"

struct job_st {
	int cps;
	int token;
	int burst;
	int pos;
};

static struct job_st *jobs[JOB_MAX];
static int inited = 0;
static struct sigaction alrm_action_save;

/*
 * 函数指针
 * 处理带有信息来源的事件处理
 * */
static void alrm_action(int s, siginfo_t *info, void *unused)
{

	// 屏蔽除了内存发送出来的信号，避免其他程序信号干扰，可以使用kill -SIGALEM pid 进行测试
	if(info->si_code != SI_KERNEL)
	{
		printf("siginal is illegal！！！\n");
		return;
	}

	// 对各个令牌进行累加
	for (int i = 0; i < JOB_MAX; i++) {
		if(jobs[i] != NULL)
		{
			jobs[i]->token += jobs[i]->cps;
			if(jobs[i]->token > jobs[i]->burst)
			{
			 	jobs[i]->token = jobs[i]->burst;	
			}
		}
	}
}

static void module_unload(void)
{
	// 恢复现场
	struct itimerval itv;

    sigaction(SIGALRM, &alrm_action_save, NULL);

    itv.it_interval.tv_sec = 0;
    itv.it_interval.tv_usec = 0;
    itv.it_value.tv_sec = 0;
    itv.it_value.tv_usec = 0;
    setitimer(ITIMER_REAL, &itv, NULL);
	
	for (int i = 0; i < JOB_MAX; i++) {
		free(jobs[i]);
	}
}

static void module_load(void)
{

	struct sigaction siac;
	struct itimerval itv;
	
	siac.sa_sigaction = alrm_action;
	sigemptyset(&siac.sa_mask);
	siac.sa_flags = SA_SIGINFO; // 表示信号触发的时候带有3个参数的指针函数
	sigaction(SIGALRM, &siac, &alrm_action_save);

	itv.it_interval.tv_sec = 1;
	itv.it_interval.tv_usec = 0;
	itv.it_value.tv_sec = 1;
	itv.it_value.tv_usec = 0;
	setitimer(ITIMER_REAL, &itv,NULL); // 信号 1s 定时发出

	// 钩子函数，卸载当前模块
	atexit(module_unload);
}

static int get_free_pos()
{
	for (int i = 0; i < JOB_MAX; i++) {
		if(jobs[i] == NULL)
		{
			return i;
		}
	}
	return -1;
}

job_t *job_init(int cps, int burst)
{
	struct job_st *me;
	int pos;
	if(!inited)
	{
		module_load();
		inited = 1;
	}

	pos = get_free_pos();
	if(pos < 0)
	{
		return NULL;
	}

	me = malloc(sizeof(*me));
	if(me == NULL)
	{
		return NULL;
	}

	me->token = 0;
	me->burst = burst;
	me->cps = cps;
	me->pos = pos;

	jobs[pos] = me;

	return me;
}

/*
 *获取令牌
 * */
int job_fetchtoken(job_t *job, int size)
{
	struct job_st *ptr = job;

	if(size <= 0)
	{
		return -EINVAL;
	}

	while(ptr->token <= 0)
	{
		pause();
	}
	
	int n = (ptr->token > size ? size : ptr->token);
	ptr->token -= n;

	return n;
}

/*
 * 存放令牌
 * */
int job_returntoken(job_t *ptr, int size)
{
	struct job_st *me = ptr;
	if(size <= 0)
	{
		return -EINVAL;
	}
	me->token += size;
	if(me->token > me->burst)
	{
		me->token = me->burst;
	}
	return -1;
}

int job_destory(job_t *ptr)
{
	struct job_st *me = ptr;
	jobs[me->pos] = NULL;
	free(ptr);
	return 0;
}

